package org.scboy.utils.entitys.coobi;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.scboy.utils.enums.coobi.GMethod;
import org.scboy.utils.enums.coobi.OrderType;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.convert.Convert;

/**
 * 
 * 实体封装
 *
 * @author 四川耗子
 * @email 125167488@qq.com
 * @date 2017年6月26日
 */
public class Model extends LinkedHashMap<String, Object> {
	
	//返回列
	private Map<String,String> resultColumn=new HashMap<String,String>();
	
	//不返回列
	private Map<String,String> noResultColumn=new HashMap<String,String>();
	
	private int orderIndex = 0;

	public Model() {
	};

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 获取32位整数
	 * 
	 * @param key
	 * @return
	 */
	public Integer getInt(String key) {

		return this.get(key) == null ? null : Convert.toInt(Convert.toDouble(this.get(key)));
	}

	/**
	 * 获取双浮点数
	 * 
	 * @param key
	 * @return
	 */
	public Double getDouble(String key) {
		return this.get(key) == null ? null : Convert.toDouble(this.get(key));
	}

	/**
	 * 获取时间类型
	 * 
	 * @param key
	 * @return
	 */
	public Date getDate(String key) {
		return this.get(key) == null ? null : Convert.toDate(this.get(key));
	}

	/**
	 * 获取时间类型
	 * 
	 * @param key
	 * @return
	 */
	public Date getDateTime(String key) {
		return this.get(key) == null ? null :Convert.toDate(this.get(key));
	}

	/**
	 * 获取二进制流
	 * 
	 * @param key
	 * @return
	 */
	public byte [] getBytes(String key) {
		Object obj=this.get(key);
		if(obj==null)return null;
		else if(obj instanceof byte[]){
			return (byte[]) this.get(key);
		}else if(obj instanceof ArrayList){
			List<?> list=(List<?>)obj;
			byte [] data=new byte[list.size()];
			for (int i = 0; i < list.size(); i++) {
				data[i]=Convert.toByte(list.get(i));
			}
			return data;
		}else{
			return null;
		}
	}

	/**
	 * 获取字符串
	 * 
	 * @param key
	 * @return
	 */
	public String getString(String key) {
		return this.get(key) == null ? null : Convert.toStr(this.get(key));
	}

	/**
	 * 获取高精度浮点型
	 * 
	 * @param key
	 * @return
	 */
	public BigDecimal getBigDecimal(String key) {
		return this.get(key) == null ? null : Convert.toBigDecimal(this
				.get(key));
	}

	/**
	 * 获取布尔类型
	 * 
	 * @param key
	 * @return
	 */
	public Boolean getBoolean(String key) {
		if (this.get(key) == null) {
			return false;
		} else {
			Object value = this.get(key);
			if (value instanceof Double || value instanceof Float
					|| value instanceof BigDecimal) {
				value = Convert.toInt(value);
			}
			return Convert.toBool(value);
		}
	}

	/**
	 * 获取64位长整数
	 * 
	 * @param key
	 * @return
	 */
	public Long getLong(String key) {
		return this.get(key) == null ? null : Convert.toLong(this.get(key));
	}

	/**
	 * 获取单精度类型
	 * 
	 * @param key
	 * @return
	 */
	public Float getFloat(String key) {
		return this.get(key) == null ? null : Convert.toFloat(this.get(key));
	}

	/**
	 * 获取16为长整数
	 * 
	 * @param key
	 * @return
	 */
	public Short getShort(String key) {
		return this.get(key) == null ? null : Convert.toShort(this.get(key));
	}

	/**
	 * 创建一个model实例。
	 * 
	 * @return
	 */
	public static Model create() {
		return new Model();
	}

	/**
	 * 添加一条数据到模型中。
	 * 
	 * @param column
	 * @param data
	 * @return
	 */
	public Model add(String column, Object data) {
		this.put(column, data);
		return this;
	}

	/**
	 * 设置排序列 ASC
	 * 
	 * @param column
	 * @return
	 */
	public Model orderBy(String column) {
		return orderBy(column, null);
	}

	/**
	 * 设置排序
	 * 
	 * @param column
	 * @param type
	 * @return
	 */
	public Model orderBy(String column, OrderType type) {
		if (type != null) {
			this.put(column + "-" + type.toString().toUpperCase(Locale.ENGLISH), orderIndex);
		} else {
			this.put(column += "-" + OrderType.ASC.toString().toUpperCase(Locale.ENGLISH),
					orderIndex);
		}
		orderIndex++;
		return this;
	}

	/**
	 * 设置分组列
	 * 
	 * @param column
	 * @return
	 */
	public Model groupBy(String column) {
		this.put(column + "-group", null);
		return this;
	}

	/**
	 * 设置分组列
	 * 
	 * @param column
	 *            分组
	 * @param method
	 *            分组方法
	 * @return
	 */
	public Model groupBy(String column, GMethod method) {
		if (method != null) {
			this.put(column + "-" + method.toString(), null);
		}
		return this;
	}

	/**
	 * AND小于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model LT(String column, Object value) {
		this.put(column + "-lt", value);
		return this;
	}

	/**
	 * AND大于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model GT(String column, Object value) {
		this.put(column + "-gt", value);
		return this;
	}

	/**
	 * AND大于等于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model GE(String column, Object value) {
		this.put(column + "-ge", value);
		return this;
	}

	/**
	 * AND小于等于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model LE(String column, Object value) {
		this.put(column + "-le", value);
		return this;
	}

	/**
	 * AND不等于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model NE(String column, Object value) {
		this.put(column + "-ne", value);
		return this;
	}

	/**
	 * AND 模糊查询，参数根据情况自己带左右%
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model LIKE(String column, Object value) {
		this.put(column + "-lk", value);
		return this;
	}

	/**
	 * AND 包含条件in
	 * 
	 * @param column
	 * @param value
	 *            数组或者list
	 * @return
	 */
	public Model IN(String column, Object value) {
		this.put(column + "-in", value);
		return this;
	}

	/**
	 * AND 不包含条件not in
	 * 
	 * @param column
	 * @param value
	 *            数组或者list
	 * @return
	 */
	public Model NOTIN(String column, Object value) {
		this.put(column + "-nin", value);
		return this;
	}

	// OR
	/**
	 * 相等条件
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model or(String column, Object value) {
		this.put(column + "-or", value);
		return this;
	}

	/**
	 * OR小于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model orLT(String column, Object value) {
		this.put(column + "-lt-or", value);
		return this;
	}

	/**
	 * OR大于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model orGT(String column, Object value) {
		this.put(column + "-gt-or", value);
		return this;
	}

	/**
	 * OR大于等于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model orGE(String column, Object value) {
		this.put(column + "-ge-or", value);
		return this;
	}

	/**
	 * OR小于等于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model orLE(String column, Object value) {
		this.put(column + "-le-or", value);
		return this;
	}

	/**
	 * OR 不等于
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model orNE(String column, Object value) {
		this.put(column + "-ne-or", value);
		return this;
	}
	
	/**
	 * OR 模糊查询
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Model orLIKE(String column, Object value) {
		this.put(column + "-lk-or", value);
		return this;
	}

	/**
	 * OR 包含条件
	 * 
	 * @param column
	 * @param value
	 *            数组或者list
	 * @return
	 */
	public Model orIN(String column, Object value) {
		this.put(column + "-in-or", value);
		return this;
	}

	/**
	 * OR 不包含条件
	 * 
	 * @param column
	 * @param value
	 *            数组或者list
	 * @return
	 */
	public Model orNOTIN(String column, Object value) {
		this.put(column + "-nin-or", value);
		return this;
	}

	/**
	 * 添加一个逻辑子查询 or
	 * 
	 * @param model
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Model or(Model model) {
		if (!this.containsKey("coobi_db_or_and_query")) {
			this.put("coobi_db_or_and_query", new ArrayList<ChildQuery>());
		}
		List<ChildQuery> listQuery = (List<ChildQuery>) this
				.get("coobi_db_or_and_query");
		ChildQuery cq = new ChildQuery();
		cq.setJoin("OR");
		cq.setQueryModel(model);
		listQuery.add(cq);
		return this;
	}

	/**
	 * 添加一个逻辑子查询 and
	 * 
	 * @param model
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Model and(Model model) {
		if (!this.containsKey("coobi_db_or_and_query")) {
			this.put("coobi_db_or_and_query", new ArrayList<ChildQuery>());
		}
		List<ChildQuery> listQuery = (List<ChildQuery>) this
				.get("coobi_db_or_and_query");
		ChildQuery cq = new ChildQuery();
		cq.setJoin("AND");
		cq.setQueryModel(model);
		listQuery.add(cq);
		return this;
	}

	@SuppressWarnings("unchecked")
	public Model getModel(String column) {
		if(this.get(column) instanceof Model) {
			return (Model) this.get(column);
		}else {
			Map<String, Object> map=(Map<String, Object>)this.get(column);
			if(map==null)return null;
			Model result=Model.create();
			for (String key : map.keySet()) {
				result.add(key, map.get(key));
			}
			return result;
		}
	}
	
	@SuppressWarnings("rawtypes")
	public static Model convert(Object data) {
		Map map=null;
		if(data instanceof Map) {
			map=(Map)data;
		}
		if(map==null)return null;
		Model result=Model.create();
		for (Object key : map.keySet()) {
			result.add(Convert.toStr(key), map.get(key));
		}
		return result;
	}
	
	/**
	 * Model转换实体对象
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	public <T> T toEntity(Class<T> clazz) {
		CopyOptions options=new CopyOptions();
		//忽略空值
		options.setIgnoreNullValue(true);
		//忽略异常
		options.setIgnoreError(true);
		return BeanUtil.toBean(this, clazz,options);
	}
	
	/**
	 * 返回列
	 * @param column
	 * @return
	 */
	public Model addRc(String column) {
		this.resultColumn.put(column,column);
		return this;
	}

	/**
	 * 不返回列
	 * @param column
	 * @return
	 */
	public Model addNrc(String column) {
		this.noResultColumn.put(column,column);
		return this;
	}
	
	/**
	 * 获取返回列集合
	 * @return
	 */
	public Set<String> rcColumns(){
		return resultColumn.keySet();
	}
	
	/**
	 * 获取不返回列集合
	 * @return
	 */
	public Set<String> nrcColumns(){
		return noResultColumn.keySet();
	}
	/**
	 * 检查列是否允许返回
	 * @param column
	 * @return
	 */
	public boolean checkRc(String column) {
		
		//如果配置了返回类，只验证返回列，不在返回列范围不返回
		if(resultColumn.size()> 0) {
			return resultColumn.containsKey(column);
		}else if(noResultColumn.containsKey(column)) {
			//如果未配置返回列的情况，检查是否配置了不返回列
			return false;
		}else {
			return true;
		}
	}
	
	public Limit getLimit() {
		Model limitModel=this.getModel("limit");
		if(limitModel!=null) {
			return Limit.createLimit(limitModel.getInt("currentPage"), limitModel.getInt("pageSize"));
		}else {
			return Limit.createLimit(0, 0);
		}
	}
	
	public String [] getStringArray(String key){
		ArrayList<?> array=(ArrayList<?>)this.get(key);
		if(array==null) {
			return null;
		}else {
			String [] arr=new String[array.size()];
			for(int i=0;i<array.size();i++) {
				arr[i]=Convert.toStr(array.get(i));
			}
			return arr;
		}
	}

	public int [] getIntArray(String key){
		ArrayList<?> array=(ArrayList<?>)this.get(key);
		if(array==null) {
			return null;
		}else {
			int [] arr=new int[array.size()];
			for(int i=0;i<array.size();i++) {
				arr[i]=Convert.toInt(array.get(i));
			}
			return arr;
		}
	}
	

	public double [] getDoubleArray(String key){
		ArrayList<?> array=(ArrayList<?>)this.get(key);
		if(array==null) {
			return null;
		}else {
			double [] arr=new double[array.size()];
			for(int i=0;i<array.size();i++) {
				arr[i]=Convert.toDouble(array.get(i));
			}
			return arr;
		}
	}
	
	@SuppressWarnings("rawtypes")
	public List<Model> getList(String key){
		List<Model> list=new ArrayList<Model>();
		ArrayList<?> array=(ArrayList<?>)this.get(key);
		for (Object object : array) {
			if(object instanceof Model) {
				list.add((Model)object);
			}else if(object instanceof Map) {
				Map map=(Map)object;
				Model model=Model.create();
				for (Object keyName : map.keySet()) {
					model.add(Convert.toStr(keyName), map.get(keyName));
				}
				list.add(model);
			}else {
				throw new RuntimeException("无法转换。");
			}
		}
		return list;
	}
}
